package com.leyou.item.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.leyou.common.constants.MQConstants;
import com.leyou.common.exception.pojo.ExceptionEnum;
import com.leyou.common.exception.pojo.LyException;
import com.leyou.common.pojo.PageResult;
import com.leyou.common.utils.BeanHelper;
import com.leyou.item.dto.SpuDTO;
import com.leyou.item.entity.Category;
import com.leyou.item.entity.Sku;
import com.leyou.item.entity.Spu;
import com.leyou.item.entity.SpuDetail;
import com.leyou.item.mapper.SkuMapper;
import com.leyou.item.mapper.SpuDetailMapper;
import com.leyou.item.mapper.SpuMapper;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Transactional
public class GoodsService extends ServiceImpl<SkuMapper, Sku> {

    @Autowired
    private SpuMapper spuMapper;

    @Autowired
    private SpuDetailMapper spuDetailMapper;

    @Autowired
    private SkuMapper skuMapper;

    @Autowired
    private BrandService brandService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private AmqpTemplate amqpTemplate;

    public PageResult<SpuDTO> spuPageQuery(Integer page, Integer rows, String key, Boolean saleable) {
        //封装mybatis-plus的分页对象
        IPage<Spu> iPage = new Page<>(page, rows);
        //创建一个封装复杂条件的对象
        QueryWrapper<Spu> wrapper = Wrappers.query();
        //判断是否有查询条件
        if(StringUtils.isNotEmpty(key)){
            wrapper.like("name", key);
        }
        //判断是否有上下架的条件
        if(saleable!=null){
            //mysql数据库中用tinyint可以直接当布尔值。数据库中所有非0都转为java中的true，0则为false。java中的true到mysql中则为1，false则为0。
            wrapper.eq("saleable", saleable);
        }
        //分页查询Spu
        iPage = spuMapper.selectPage(iPage, wrapper);
        //获取Spu集合
        List<Spu> spus = iPage.getRecords();
        //判空
        if(CollectionUtils.isEmpty(spus)){
            throw new LyException(ExceptionEnum.GOODS_NOT_FOUND);
        }
        //讲Spu集合转成SpuDTO集合
        List<SpuDTO> spuDTOS = BeanHelper.copyWithCollection(spus, SpuDTO.class);
        //给SpuDTO集合中每个SpuDTO对象的分类名称和品牌名称赋值
        handlerCategoryNamesAndBrandName(spuDTOS);
        //创建一个自定义的分页对象
        PageResult<SpuDTO> result = new PageResult<>(
                iPage.getTotal(),
                iPage.getPages(),
                spuDTOS
        );
        return result;
    }

    private void handlerCategoryNamesAndBrandName(List<SpuDTO> spuDTOS) {
        //遍历
        spuDTOS.forEach(spuDTO -> {
            //获取品牌id
            Long brandId = spuDTO.getBrandId();
            //根据品牌id获取品牌名称
            String brandName = brandService.findBrandById(brandId).getName();
            //将品牌名称赋值给SpuDTO
            spuDTO.setBrandName(brandName);

            //根据分类的id的集合获取分类名称的拼接
            String categoryNames = categoryService.findCategoriesByIds(spuDTO.getCategoryIds())//获取List<Category>集合
                    .stream()//转成流  其实就是方便遍历
                    .map(Category::getName)//对每一个Category对象执行自身类的方法引用getName，得到分类名称name
                    .collect(Collectors.joining("|"));//将所有分类的名称收集起来，拼接成以"|"隔开的字符串
            //将分类名称的拼接赋值给SpuDTO
            spuDTO.setCategoryName(categoryNames);
        });
    }

    public void saveGoods(SpuDTO spuDTO) {
        try {
            //将SpuDTO对象转成Spu
            Spu spu = BeanHelper.copyProperties(spuDTO, Spu.class);
            //新添加的商品要设置为下架
            spu.setSaleable(false);
            //保存Spu
            spuMapper.insert(spu);

            //获取Spu的id
            Long spuId = spu.getId();

            //获取SpuDetail对象
            SpuDetail spuDetail = spuDTO.getSpuDetail();
            //给SpuDetail的主键赋值
            spuDetail.setSpuId(spuId);
            //保存SpuDetail
            spuDetailMapper.insert(spuDetail);

            //获取Sku集合
            List<Sku> skus = spuDTO.getSkus();
            //给Sku集合中每个Sku的SpuId赋值
            skus.forEach(sku -> {
                sku.setSpuId(spuId);
            });
            //批量保存sku
            saveBatch(skus);
        }catch (Exception e){
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }
    }

    /**
     * 商品上下架
     * @param id
     * @param saleable
     */
    public void updateSaleable(Long id, Boolean saleable) {
        Spu entity = new Spu();
        entity.setId(id);
        entity.setSaleable(saleable);
        int count = spuMapper.updateById(entity);
        if(count!=1){
            throw new LyException(ExceptionEnum.UPDATE_OPERATION_FAIL);
        }

        //保证商品数据数据库与索引库和静态页的同步
        //同步操作【对当前业务有影响】通过feign来实现同步

        //指定routingKey
        String routingKey = saleable ? MQConstants.RoutingKey.ITEM_UP_KEY : MQConstants.RoutingKey.ITEM_DOWN_KEY;
        //异步操作【对当前页面无影响】通过MQ来实现异步
        amqpTemplate.convertAndSend(MQConstants.Exchange.ITEM_EXCHANGE_NAME, routingKey, id);

    }

    public List<Sku> findSkusBySpuId(Long id) {
        Sku entity = new Sku();
        entity.setSpuId(id);
        QueryWrapper<Sku> wrapper = Wrappers.query(entity);
        List<Sku> skus = skuMapper.selectList(wrapper);
        if(CollectionUtils.isEmpty(skus)){
            throw new LyException(ExceptionEnum.GOODS_NOT_FOUND);
        }
        return skus;
    }

    public SpuDetail findSpuDetailById(Long id) {
        SpuDetail spuDetail = spuDetailMapper.selectById(id);
        if(spuDetail==null){
            throw new LyException(ExceptionEnum.GOODS_NOT_FOUND);
        }
        return spuDetail;
    }

    public SpuDTO findSpuDTOById(Long id) {
        //根据spuId查询Spu对象
        Spu spu = spuMapper.selectById(id);
        //判空
        if(spu==null){
            throw new LyException(ExceptionEnum.GOODS_NOT_FOUND);
        }
        //将Spu转成SpuDTO
        SpuDTO spuDTO = BeanHelper.copyProperties(spu, SpuDTO.class);
        //根据spuId查询Sku集合
        List<Sku> skus = findSkusBySpuId(id);
        spuDTO.setSkus(skus);
        //根据spuId查询SpuDetail对象
        SpuDetail spuDetail = findSpuDetailById(id);
        spuDTO.setSpuDetail(spuDetail);
        return spuDTO;
    }

    public List<Sku> findSkusByIds(List<Long> ids) {
        List<Sku> skus = skuMapper.selectBatchIds(ids);
        if(CollectionUtils.isEmpty(skus)){
            throw new LyException(ExceptionEnum.GOODS_NOT_FOUND);
        }
        return skus;
    }

    public void minusStock(Map<Long, Integer> paramsMap) {
        try {
            paramsMap.entrySet().forEach(entry->{
                Long skuId = entry.getKey();//要减的sku的id
                Integer num = entry.getValue();//购买的数量
                //注意：在java的业务层先处理器好数据，再去更新，是会有线程安全问题的。
                //根据skuId查询Sku对象
//                Sku sku = skuMapper.selectById(skuId);
//                //封装条件
//                Sku entity = new Sku();
//                entity.setId(skuId);
//                entity.setStock(sku.getStock()-num);
//                skuMapper.updateById(entity);

                //正确做法：将库存的减少和更新操作都挪到数据库来做
                skuMapper.minusStock(skuId, num);
            });
        }catch (Exception e){
            throw new LyException(ExceptionEnum.UPDATE_OPERATION_FAIL);
        }

    }


    /**
     * 根据skuId查询sku属性
     * */
    public Sku findSkuById(Long skuId) {
        Sku sku = skuMapper.selectById(skuId);
        return sku;
    }



}
